package net.vinote.sosa.core.module.log;

import java.io.File;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import net.vinote.smart.socket.lang.StringUtils;

public class RunLogger {

	private static RunLogger runlogger;

	private Logger logger = null;;

	private volatile LoggerStatus status = LoggerStatus.UNINITIALIZE;

	private LinkedBlockingQueue<LogRecord> logQueue;

	private LoggerThread logThread;

	private LoggerConfig config;

	private RunLogger() {
		logger = Logger.getLogger(RunLogger.class.getName());
		logger.setUseParentHandlers(false);
		logger.getParent().setLevel(Level.ALL);
	}

	public static RunLogger getLogger() {
		if (runlogger == null) {
			synchronized (RunLogger.class) {
				if (runlogger == null) {
					runlogger = new RunLogger();
				}
			}
		}
		return runlogger;
	}

	public synchronized void init(LoggerConfig config) {

		if (LoggerStatus.UNINITIALIZE != status && LoggerStatus.TEMP_ENABLED != status) {
			throw new LoggerSystemException("could not execute Logger init method,RunLogger's current status is "
				+ status);
		}
		try {
			// 移除已注册的Handler
			Handler[] handls = logger.getHandlers();
			if (handls != null) {
				for (Handler h : handls) {
					logger.removeHandler(h);
				}
			}

			logger.setLevel(config.getLevel());

			// 是否当前日志需要输出至文件,则先检查日志文件存放目录是否存在
			if (config.isLog2File() || config.isErr2File() || config.isOut2File()) {
				File file = new File(config.getLogDir());
				if (!file.isDirectory()) {
					file.mkdirs();
				}
			}
			// 设置日志文件Handler
			if (config.isLog2File()) {
				logger.addHandler(config.getLogFileHandler());
			}

			// 设置控制台日志Handler
			if (config.isLog2console()) {
				logger.addHandler(config.getConsoleHandler());
			}
			// 设置运行时异常的Handler
			if (config.isErr2File()) {
				logger.addHandler(config.getErrorFileHandler());
			}

			// 设置System.out的Handler
			if (config.isOut2File()) {
				logger.addHandler(config.getOutFileHandler());
			}
			// 启动日志输出线程
			if (!config.isSynchro()) {
				logQueue = new LinkedBlockingQueue<LogRecord>();
				logThread = new LoggerThread();
				logThread.setDaemon(true);
				logThread.setName("LoggerThread");
				logThread.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		this.config = config;
		status = LoggerStatus.ENABLED;
	}

	public void log(Throwable thrown) {

		log(Level.WARNING, thrown.getMessage(), thrown);
	}

	public void log(Level level, String msg) {

		log(level, msg, (Throwable) null);
	}

	/*
	 * public void log(Level level, DataEntry data) { log(level,
	 * "HexData -->\r\n" + StringFunction.toHexString(data.getData()),
	 * (Throwable) null); }
	 */

	public void log(Level level, String msg, byte[] data) {
		log(level, msg + "\r\n" + StringUtils.toHexString(data), (Throwable) null);
	}

	public void log(Level level, String msg, Throwable thrown) {
		// 使用未初始化的日至系统时,自动提供一个临时配置
		if (status == LoggerStatus.UNINITIALIZE) {
			setInnerLoggerCfg();
			status = LoggerStatus.TEMP_ENABLED;
		}
		if (status != LoggerStatus.ENABLED && status != LoggerStatus.TEMP_ENABLED) {
			throw new LoggerSystemException("RunLogg's status is " + status);
		}
		try {
			LogRecord record = new LogRecord(level, null);
			record.setMessage(msg);
			record.setThrown(thrown);
			if (logThread == null || config != null && config.isSynchro()) {
				logger.log(record);
			} else {
				boolean lookingForLogger = true;
				StackTraceElement[] stackElement = new Throwable().getStackTrace();
				for (StackTraceElement stack : stackElement) {
					String cname = stack.getClassName();
					if (lookingForLogger) {
						// Skip all frames until we have found the first logger
						// frame.
						if (cname.matches(this.getClass().getName())) {
							lookingForLogger = false;
						}
					} else {
						if (!cname.matches(this.getClass().getName())) {
							String simpleClassName = cname.substring(cname.lastIndexOf(".") + 1);
							record.setMessage("[" + simpleClassName + "(" + stack.getMethodName() + ":"
								+ stack.getLineNumber() + ")] " + record.getMessage());
							break;
						}
					}
				}
				logQueue.put(record);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 内置一个日至系统配置
	 */
	private void setInnerLoggerCfg() {
		LoggerConfig cfg = new LoggerConfig();
		cfg.setLog2console(true);
		cfg.setLevel(Level.ALL);
		init(cfg);
	}

	/**
	 * 日志输出线程
	 *
	 * @author 郑俊伟
	 *
	 */
	private class LoggerThread extends Thread {

		@Override
		public void run() {

			while (status == LoggerStatus.UNINITIALIZE || status == LoggerStatus.ENABLED
				|| status == LoggerStatus.TEMP_ENABLED) {
				try {
					do {
						LogRecord logRecord = logQueue.take();
						logger.log(logRecord);
					} while (!logQueue.isEmpty());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			status = LoggerStatus.STOPED;
			logger.log(new LogRecord(Level.SEVERE, "RunLogger System is stopped"));
		}

		public void stopLogger() {
			status = LoggerStatus.STOPING;
			try {
				logQueue.put(new LogRecord(Level.FINE, "RunLogger System is going to stopped"));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获取当前日志系统的日志级别
	 *
	 * @return
	 */
	public Level getLoggerLevel() {
		return config.getLevel();
	}

	/**
	 *
	 **/
	public void stop() {
		logThread.stopLogger();
	}
}

class LoggerEvent {
	private LogRecord record;

	public LogRecord getRecord() {
		return record;
	}

	public void setRecord(LogRecord record) {
		this.record = record;
	}

}

/**
 * 系统状态枚举
 *
 * @author 郑俊伟
 *
 */
enum LoggerStatus {
	/** 未初始化 */
	UNINITIALIZE,
	/** 临时可用 */
	TEMP_ENABLED,
	/** 可用 */
	ENABLED,
	/** 停止中 */
	STOPING,
	/** 已停止 */
	STOPED,
	/** 关闭中 */
	Closing,
	/** 已关闭 */
	Closed;
}